package com.example.ms;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;


import java.io.*;

import java.net.URI;
import java.util.Arrays;
import java.util.List;

public class AudioController {

    private static Process process;

    @FXML
    private Button play;

    @FXML
    private Button stop;

    @FXML
    private TextArea outContext;

    // 音频流
    private InputStream inputStream;

    @FXML
    private TextArea inContext;

    /**
     * 连接FunASR按钮
     */
    @FXML
    private Button connect;
    /**
     * 关闭FunASR连接按钮
     */
    @FXML
    private Button close;

    @FXML
    private TextField connectUrl;

    private FunASRWebSocketClient wsClient;

    static int sendChunkSize = 1920;


    public void playAudio() throws IOException {
        if (wsClient == null || wsClient.isClosed()){
            outContext.appendText("\n未连接FunASR");
            return;
        }
        play.setDisable(true);
        stop.setDisable(false);
        List<String> commands = Arrays.asList(
                "ffmpeg",
                "-f", "dshow",
                "-i", "audio=\"virtual-audio-capturer\"",
                "-f", "s16le",
                "-ar", "16000",
                "-ac", "1",
                "-b:v", "128",
                "-y", "-"
                );
        ProcessBuilder builder = new ProcessBuilder(commands);
        if(process != null) {
            process.destroy();
        }
        process = builder.start();
        inputStream = process.getInputStream();
        new Thread(() ->{
            byte[] buffer = new byte[sendChunkSize];
            int readSize = 0;
            int chunkSize = sendChunkSize;
            try {
                while ((readSize = inputStream.read(buffer, 0, buffer.length)) > 0) {
                    if (readSize == chunkSize) {
                        wsClient.send(buffer);
                    } else {
                        // 发送剩余的音频
                        byte[] tmpBytes = new byte[readSize];
                        for (int i = 0; i < readSize; i++) {
                            tmpBytes[i] = buffer[i];
                        }
                        wsClient.send(tmpBytes);
                    }
                    Thread.sleep(chunkSize / 32);
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
    }

    public static int getSleepDelta(int dataSize, int sampleRate) {
        return (dataSize * 10 * 8000) / (160 * sampleRate);
    }



    public void stopAudio() throws IOException {
        // 发送eof
        JSONObject obj = new JSONObject();
        obj.append("is_speaking",Boolean.FALSE);
        wsClient.send(obj.toString());
        OutputStream outputStream = process.getOutputStream();
        outputStream.write("q".getBytes());
        outputStream.flush();
        process.destroy();
        play.setDisable(false);
        if (outContext.getText().length()>0) {
            outContext.appendText("\n");
        }
        inContext.setText("");
        stop.setDisable(true);
    }


    public void connectWS() {
        if (wsClient == null || wsClient.isClosed()){
            String url = connectUrl.getText();
            if(StrUtil.isBlank(url)){
                outContext.setText("请输入地址");
                return;
            }
            connect.setDisable(true);
            outContext.appendText("\n正在连接..." + url);
            wsClient = new FunASRWebSocketClient(URI.create(url), outContext,inContext,connect,close);
            wsClient.connect();
        }else {
            outContext.appendText("\n已连接,无法在开启新连接");
        }
    }

    public void closeWS(){
        if (wsClient!=null){
            wsClient.close();
            wsClient = null;
        }
    }

    /**
     * 处理窗口关闭事件 关闭WebSocket连接
     */
    public void setStage(Stage primaryStage) {
        primaryStage.setOnCloseRequest(event -> {
            if (wsClient!=null){
                if (!wsClient.isClosed()) {
                    wsClient.close();
                }
            }
            primaryStage.close();
        });
    }
}